import EventEmitter from 'events';
import Visibility from 'visibilityjs';
import StateMachine from 'fsm-as-promised';
import ScanProvider from "./ScanProvider";
import Analyzer from "./Analyzer";

export default class Scanner extends EventEmitter {
    constructor(opts) {
        super();

        this.video = this._configureVideo(opts);
        this.mirror = opts.mirror !== false;
        this.backgroundScan = opts.backgroundScan !== false;
        this._continuous = opts.continuous !== false;
        this._analyzer = new Analyzer(this.video);
        this._camera = null;

        let captureImage = opts.captureImage || false;
        let scanPeriod = opts.scanPeriod || 1;
        let refractoryPeriod = opts.refractoryPeriod || 5 * 1000;

        this._scanner = new ScanProvider(
            this,
            this._analyzer,
            captureImage,
            scanPeriod,
            refractoryPeriod
        );
        this._fsm = this._createStateMachine();

        Visibility.change((e, state) => {
            if (state === 'visible') {
                setTimeout(() => {
                    if (this._fsm.can('activate')) {
                        this._fsm.activate();
                    }
                }, 0);
            } else {
                if (!this.backgroundScan && this._fsm.can('deactivate')) {
                    this._fsm.deactivate();
                }
            }
        });

        this.addListener('active', () => {
            this.video.classList.remove('inactive');
            this.video.classList.add('active');
        });

        this.addListener('inactive', () => {
            this.video.classList.remove('active');
            this.video.classList.add('inactive');
        });

        this.emit('inactive');
    }

    scan() {
        return this._scanner.scan();
    }
    //update by wenquan 添加摄像头启动类型，auto为后置摄像头，rear为后置摄像头，front为前置摄像头
    async start(camera = null, cameraType = 'auto') {
        console.log('开始启动扫描');
        if (this._fsm.can('start')) {
            await this._fsm.start({ camera: camera, cameraType: cameraType });
        } else {
            await this._fsm.stop();
            await this._fsm.start({ camera: camera, cameraType: cameraType });
        }
    }

    async stop() {
        if (this._fsm.can('stop')) {
            await this._fsm.stop();
        }
    }

    set captureImage(capture) {
        this._scanner.captureImage = capture;
    }

    get captureImage() {
        return this._scanner.captureImage;
    }

    set scanPeriod(period) {
        this._scanner.scanPeriod = period;
    }

    get scanPeriod() {
        return this._scanner.scanPeriod;
    }

    set refractoryPeriod(period) {
        this._scanner.refractoryPeriod = period;
    }

    get refractoryPeriod() {
        return this._scanner.refractoryPeriod;
    }

    set continuous(continuous) {
        this._continuous = continuous;

        if (continuous && this._fsm.current === 'active') {
            this._scanner.start();
        } else {
            this._scanner.stop();
        }
    }

    get continuous() {
        return this._continuous;
    }

    set mirror(mirror) {
        this._mirror = mirror;

        if (mirror) {
            this.video.style.MozTransform = 'scaleX(-1)';
            this.video.style.webkitTransform = 'scaleX(-1)';
            this.video.style.OTransform = 'scaleX(-1)';
            this.video.style.msFilter = 'FlipH';
            this.video.style.filter = 'FlipH';
            this.video.style.transform = 'scaleX(-1)';
        } else {
            this.video.style.MozTransform = null;
            this.video.style.webkitTransform = null;
            this.video.style.OTransform = null;
            this.video.style.msFilter = null;
            this.video.style.filter = null;
            this.video.style.transform = null;
        }
    }

    get mirror() {
        return this._mirror;
    }

    async _enableScan(camera, cameraType) {
        this._camera = camera || this._camera;
        if (!this._camera) {
            throw new Error('Camera is not defined.');
        }
        console.log('摄像头类型：' + cameraType);
        let stream = await this._camera.start(cameraType);
        this.video.srcObject = stream;

        if (this._continuous) {
            this._scanner.start();
        }
    }

    _disableScan() {
        this.video.src = '';

        if (this._scanner) {
            this._scanner.stop();
        }

        if (this._camera) {
            this._camera.stop();
        }
    }

    _configureVideo(opts) {
        if (opts.video) {
            if (opts.video.tagName !== 'VIDEO') {
                throw new Error('Video must be a <video> element.');
            }
        }

        let video = opts.video || document.createElement('video');
        video.setAttribute('autoplay', 'autoplay');

        return video;
    }

    _createStateMachine() {
        return StateMachine.create({
            initial: 'stopped',
            events: [
                {
                    name: 'start',
                    from: 'stopped',
                    to: 'started',
                },
                {
                    name: 'stop',
                    from: ['started', 'active', 'inactive'],
                    to: 'stopped',
                },
                {
                    name: 'activate',
                    from: ['started', 'inactive'],
                    to: ['active', 'inactive'],
                    condition: function (options) {
                        if (Visibility.state() === 'visible' || this.backgroundScan) {
                            return 'active';
                        } else {
                            return 'inactive';
                        }
                    },
                },
                {
                    name: 'deactivate',
                    from: ['started', 'active'],
                    to: 'inactive',
                },
            ],
            callbacks: {
                onenteractive: async options => {
                    let params = options.args[0];
                    console.log('1111' + params);
                    await this._enableScan(params.camera, params.cameraType);
                    this.emit('active');
                },
                onleaveactive: () => {
                    this._disableScan();
                    this.emit('inactive');
                },
                onenteredstarted: async options => {
                    await this._fsm.activate(options.args[0]);
                },
            },
        });
    }
}
